/*
 * VentanaPrincipal.cpp
 *
 *  Created on: 25/11/2009
 *      Author: luis
 */

#include "VentanaPrincipal.h"
#include "VentanaNombre.h"
#include "VentanaInfo.h"

VentanaPrincipal::VentanaPrincipal():boton_and (BOTON_AND, new ControladorBotonAnd()),
boton_or (BOTON_OR, new ControladorBotonOr()), boton_xor (BOTON_XOR, new ControladorBotonXor()),
boton_not (BOTON_NOT, new ControladorBotonNot()), boton_in (BOTON_IN, new ControladorBotonEntrada()),
boton_out (BOTON_OUT, new ControladorBotonSalida()), boton_cable (BOTON_CABLE, new ControladorBotonCable()),
boton_caja_negra(BOTON_CAJA_NEGRA, new ControladorBotonCajaNegra(cliente_programa)),

boton_rotar(BOTON_ROTAR, new ControladorBotonRotar()),
boton_traslacion (BOTON_TRASLADAR, new ControladorBotonTraslacion()),
boton_borrar (BOTON_BORRAR, new ControladorBotonBorrar()),
boton_seleccionar(BOTON_SELECCIONAR, new ControladorBotonSeleccion()),
boton_simular(BOTON_SIMULAR, new ControladorBotonSimular())
{
	contador_areas = 0;
	area_actual=0;
	abriendo_externo = false;

	tabs.set_border_width(10);
	set_default_size(1200, 900);
	set_title("Circuitos logicos");
	set_sensitive(true);
	add(caja_elementos);
	construir_botonera();
	construir_menu();
	iniciar_areas();
	Gtk::Widget* pMenubar = m_refUIManager->get_widget("/MenuBar");
	caja_elementos.pack_start(*pMenubar, Gtk::PACK_SHRINK);
	caja_elementos.pack_start(botonera, Gtk::PACK_SHRINK);
	caja_elementos.pack_start(tabs, Gtk::PACK_EXPAND_WIDGET);
	tabs.signal_switch_page().connect(sigc::mem_fun(*this,
	              &VentanaPrincipal::on_notebook_switch_page) );
	this->show_all_children();
}

void VentanaPrincipal::iniciar_areas(){
	int i;
	for (i=0; i<CANT_MAX_AREAS; i++){
		explosiones[i]=false;
		areas[i]=NULL;
	}
}

void VentanaPrincipal::construir_botonera(){
	botonera.pack_start(boton_and, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_or, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_not, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_xor, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_caja_negra, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_in, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_out, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_cable, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_traslacion, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_borrar, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_simular, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_rotar, Gtk::PACK_SHRINK);
	botonera.pack_start(boton_seleccionar, Gtk::PACK_SHRINK);
}

void VentanaPrincipal::construir_menu(){

	m_refActionGroup = Gtk::ActionGroup::create();

	//Archivo menu
	m_refActionGroup->add(Gtk::Action::create("ArchivoMenu", "Archivo"));
	//sub menu
	m_refActionGroup->add(Gtk::Action::create("ArchivoNuevo", Gtk::Stock::NEW),
	          sigc::mem_fun(*this, &VentanaPrincipal::on_menu_new));
	m_refActionGroup->add(Gtk::Action::create("ArchivoAbrir", Gtk::Stock::OPEN),
		      sigc::mem_fun(*this, &VentanaPrincipal::on_menu_open));
	m_refActionGroup->add(Gtk::Action::create("ArchivoGuardar", Gtk::Stock::SAVE),
		      sigc::mem_fun(*this, &VentanaPrincipal::on_menu_save));
	m_refActionGroup->add(Gtk::Action::create("ArchivoImprimir", Gtk::Stock::PRINT),
		      sigc::mem_fun(*this, &VentanaPrincipal::on_menu_print));
	m_refActionGroup->add(Gtk::Action::create("ArchivoCerrarActual", Gtk::Stock::CLOSE),
		      sigc::mem_fun(*this, &VentanaPrincipal::on_menu_delete_page));
	//Opciones menu
	m_refActionGroup->add(Gtk::Action::create("OpcionesMenu", "Opciones"));
	//submenu
	m_refActionGroup->add(Gtk::Action::create("OpcionesPublicar", "Publicar circuito"),
	          sigc::mem_fun(*this, &VentanaPrincipal::on_menu_publish));



	//Ayuda menu
	m_refActionGroup->add(Gtk::Action::create("AyudaMenu", "Ayuda"));
	m_refActionGroup->add(Gtk::Action::create("AyudaAcercaDe..", Gtk::Stock::ABOUT),
		      sigc::mem_fun(*this, &VentanaPrincipal::on_menu_about));
	m_refUIManager = Gtk::UIManager::create();
	m_refUIManager->insert_action_group(m_refActionGroup);
	add_accel_group(m_refUIManager->get_accel_group());

	Glib::ustring ui_info =
	        "<ui>"
	        "  <menubar name='MenuBar'>"
	        "    <menu action='ArchivoMenu'>"
			"      <menuitem action='ArchivoNuevo'/>"
	        "      <menuitem action='ArchivoAbrir'/>"
			"      <menuitem action='ArchivoGuardar'/>"
			"      <menuitem action='ArchivoImprimir'/>"
			"      <menuitem action='ArchivoCerrarActual'/>"
	        "    </menu>"
	        "    <menu action='OpcionesMenu'>"
	        "      <menuitem action='OpcionesPublicar'/>"
	        "    </menu>"
	        "    <menu action='AyudaMenu'>"
			"      <menuitem action='AyudaAcercaDe..'/>"
	        "    </menu>"
	        "  </menubar>"
	        "</ui>";
	m_refUIManager->add_ui_from_string(ui_info);
}

void VentanaPrincipal::activar_nueva_area(AreaDibujo* area){
	boton_and.set_area_activa(area);
	boton_or.set_area_activa(area);
	boton_xor.set_area_activa(area);
	boton_not.set_area_activa(area);
	boton_in.set_area_activa(area);
	boton_out.set_area_activa(area);
	boton_borrar.set_area_activa(area);
	boton_traslacion.set_area_activa(area);
	boton_cable.set_area_activa(area);
	boton_simular.set_area_activa(area);
	boton_rotar.set_area_activa(area);
	boton_caja_negra.set_area_activa(area);
	boton_seleccionar.set_area_activa(area);
}



void VentanaPrincipal::on_notebook_switch_page(GtkNotebookPage* , guint page_num){
	if ((!abriendo_externo)&&(explosiones[page_num]==false)){
		activar_nueva_area(areas[page_num]);
		if (contador_areas>0)
			areas[page_num]->set_estado(INVALIDO);
	}
	else
		explosiones[page_num]=true;
	area_actual = page_num;
}


/*
 * Funciones para manejar el menu
 */
void VentanaPrincipal::on_menu_new(){
	if (contador_areas<(CANT_MAX_AREAS-1)){
		std::string nombre = "Ingrese Nombre del circuito";
		VentanaNombre ventana(nombre);
		int resultado = ventana.run();
		if (resultado == Gtk::RESPONSE_OK){
			/*
			 * Abre una nueva zolapa para el elemento si el usuario escribio un nombre
			 */
			if (!ventana.get_nombre().empty()){
				AreaDibujo * area = new AreaDibujo(new Circuito(ventana.get_nombre()), this);
				tabs.append_page(*area, ventana.get_nombre());
				activar_nueva_area(area);
				areas[contador_areas]=area;
				this->area_actual = contador_areas;
				show_all_children();
				tabs.set_current_page(contador_areas);
				contador_areas++;
			}
		}
	}
	else{
		VentanaInfo cierre_algun_circuito("ERROR","Cierre algunos circuitos, se ha llegado al limite");
		cierre_algun_circuito.run();
	}
}


void VentanaPrincipal::on_menu_open(){
	Gtk::FileChooserDialog dialog("Please choose a file",
	          Gtk::FILE_CHOOSER_ACTION_OPEN);
	dialog.set_transient_for(*this);

	dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
	dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);

	Gtk::FileFilter filter_text;
	filter_text.set_name("Text files");
	filter_text.add_mime_type("text/plain");
	dialog.add_filter(filter_text);

	int result = dialog.run();


	switch(result)
	{
		case(Gtk::RESPONSE_OK):
	   	{
			if (contador_areas<(CANT_MAX_AREAS-1)){
				std::string filename = dialog.get_filename();
				ParserXml parser;

				/*
				 * Listas donde voy a cargar el circuito guardado
				 */
				std::string nombre;
				std::list<Compuerta*>  pListaCompuertas;
				std::list<Entrada*>  pListaEntradas;
				std::list<Salida*>  pListaSalidas;
				std::list<Cable*> pListaCables;
				std::list<ElementoExterno*>  pListaExternos;
				char *c = strdup(filename.c_str());

				/*
				 * Cargo el circuito
				 */
				int id = parser.obtener_Desde_Archivo(c, &pListaCompuertas,&pListaEntradas,&pListaSalidas, &pListaCables, &pListaExternos, &nombre);
				AreaDibujo * area = new AreaDibujo(new Circuito(&pListaEntradas,&pListaSalidas,&pListaCompuertas, &pListaCables,&pListaExternos, nombre ), this);
				Circuito* actual = area->get_circuito_actual();

				actual->set_id(id);
				area->set_nro_id(id);
				tabs.append_page(*area, area->get_circuito_actual()->get_nombre());
				activar_nueva_area(area);
				areas[contador_areas]=area;

				show_all_children();
				tabs.set_current_page(contador_areas);
				contador_areas++;

				break;
			}
			else{
				VentanaInfo cierre_algun_circuito("ERROR","Cierre algunos circuitos, se ha llegado al limite");
				cierre_algun_circuito.run();
			}
	   	}
		case(Gtk::RESPONSE_CANCEL):
    	{
			break;
    	}
		default:
		{
			break;
		}
	}
}


int VentanaPrincipal::abrir_externo(char* archivo){
	if (contador_areas<(CANT_MAX_AREAS-1)){
		abriendo_externo = true;
		ParserXml parser;

		/*
		 * Variables donde cargo el circuito
		 */
		std::string nombre;
		std::list<Compuerta*> pListaCompuertas;
		std::list<Entrada*> pListaEntradas;
		std::list<Salida*> pListaSalidas;
		std::list<Cable*> pListaCables;
		std::list<ElementoExterno*> pListaExternos;

		//Cargo el circuito

		int id = parser.obtener_Desde_Archivo(archivo, &pListaCompuertas,&pListaEntradas,&pListaSalidas, &pListaCables, &pListaExternos, &nombre);
		AreaDibujo * area = new AreaDibujo(new Circuito(&pListaEntradas,&pListaSalidas,&pListaCompuertas, &pListaCables,&pListaExternos, nombre ), this);
		area->get_circuito_actual()->set_id(id);
		area->set_nro_id(id);
		tabs.append_page(*area, area->get_circuito_actual()->get_nombre());
		areas[contador_areas]=area;
		show_all_children();
		tabs.set_current_page(contador_areas);
		contador_areas++;
		return CORRECTO;
	}
	else{
		VentanaInfo cierre_algun_circuito("ERROR","Cierre algunos circuitos, se ha llegado al limite");
		cierre_algun_circuito.run();
		return INCORRECTO;
	}
}


void VentanaPrincipal::on_menu_save(){

	if(contador_areas>0){
		Gtk::FileChooserDialog dialog("Guardando",
				  Gtk::FILE_CHOOSER_ACTION_SAVE);
		dialog.set_transient_for(*this);

		dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
		dialog.add_button("Guardar", Gtk::RESPONSE_OK);

		int result = dialog.run();

		switch(result)
		{
			case(Gtk::RESPONSE_OK):
			{
				std::string filename = dialog.get_filename();

				char *rutaArchivo = strdup(filename.c_str());

				int actual = tabs.get_current_page();

				Circuito * circ = this->areas[actual]->get_circuito_actual();
				circ->set_id(areas[actual]->get_id());
				if (circ!=NULL){
					ParserXml xml;

					//Guardo el archivo

					xml.persistir_En_Archivo(rutaArchivo,&circ->get_lista_compuertas(),&circ->get_lista_entradas()
									, &circ->get_lista_salidas(), &circ->get_lista_cables(), &circ->get_lista_elementos_externos(), &circ->get_nombre(), circ->get_id_maximo());
				}

					break;
			}
			case(Gtk::RESPONSE_CANCEL):
			{
				break;
			}
			default:
			{
				break;
			}
		}
	}
	else{
		VentanaInfo error_de_guardado("ERROR","Para guardar debe existir un circuito");
		error_de_guardado.run();
	}
}



void VentanaPrincipal::on_menu_print(){
	/*
	 * Si hay algo para imprimir, abre la ventana de impresion
	 */
	if(contador_areas>0){
		PrintWindow impresion(areas[contador_areas-1], areas[contador_areas-1]->get_circuito_actual());
		impresion.run();
	}
	else{
		VentanaInfo error_de_impresion("ERROR","Para imprimir debe existir un circuito");
		error_de_impresion.run();
	}
}

void VentanaPrincipal::on_menu_delete_page(){
	if (contador_areas>0){
		int area_previa = area_actual;
		tabs.remove_page(area_actual);
		contador_areas--;
		AreaDibujo* auxiliar = areas[area_previa];
		areas[area_previa]=NULL;
		delete auxiliar;
		int i;

		/*
		 * Reacomodo las areas
		 */
		for (i=area_previa; i<(CANT_MAX_AREAS-1); i++){
			areas[i]=areas[i+1];
			explosiones[i]=explosiones[i+1];
		}
		if(contador_areas>0){
			/*
			 * Si la zolapa activa no es una explosion activo el area
			 */
			if ((area_previa==area_actual)&&(explosiones[area_previa]==false))
				activar_nueva_area(areas[area_previa]);
		}
		else
			activar_nueva_area(NULL);
	}
}

void VentanaPrincipal::on_menu_publish(){

	if (contador_areas>0){
		if (explosiones[area_actual]==false){
			Circuito * circ = this->areas[area_actual]->get_circuito_actual();
			circ->set_id(areas[area_actual]->get_id());
			std::string ruta = "./CircuitosPublicados/";
			ruta.append(circ->get_nombre());
			char *rutaArchivo = strdup(ruta.c_str());
			if (circ!=NULL){
				ParserXml xml;
				xml.persistir_En_Archivo(rutaArchivo,&circ->get_lista_compuertas(),&circ->get_lista_entradas()
								, &circ->get_lista_salidas(), &circ->get_lista_cables(), &circ->get_lista_elementos_externos(), &circ->get_nombre(), circ->get_id_maximo());
			}
			std::string aux = "El circuito '";
			aux.append (circ->get_nombre());
			aux.append ("' se ha publicado correctamente");
			VentanaInfo circuito_publicado ("CIRCUITO PUBLICADO", aux);
			circuito_publicado.run();
		}
		else{
			VentanaInfo no_publicado ("ERROR", "No se puede publicar circuito");
			no_publicado.run();
		}
	}
	else{
		VentanaInfo no_publicado ("ERROR", "No se puede publicar circuito");
			no_publicado.run();
	}
}


void VentanaPrincipal::on_menu_about(){
	VentanaInfo info_tp("Trabajo Taller de programacion", "Trabajo practico: Circuitos Logicos 1.0 \n\nIntegrantes:\n"
			"\t\tEmiliano Orlando \n\t\tNicolas Goday \n\t\tLuis Paniagua");
	info_tp.run();
}

VentanaPrincipal::~VentanaPrincipal() {
	int i;
	for (i=0; i<CANT_MAX_AREAS; i++){
		if (areas[i]!= NULL){
			delete areas[i];
		}
	}
}
